﻿using System;
using System.Threading;

namespace Cherry.Agile.RpcService.Client
{
    /// <summary>
    /// 客户端服务提交处理流程控制器
    /// 协议V1.1
    /// </summary>
    public class ClientProcessorV11 : IClientProcessor
    {
        SynchronizationContext sysContext;
        public ClientProcessorV11()
        {sysContext = SynchronizationContext.Current; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serviceUrl"></param>
        public ClientProcessorV11(string serviceUrl,string token)
            :this()
        {
            this.ServiceUrl = serviceUrl;
            this.Token = token;
        }

        /// <summary>
        /// 发送请求处理
        /// </summary>
        /// <param name="rq">请求</param>
        public void Process(params ClientRequest[] requests)
        {
            ClientRequest rq = requests[0]; //V1.1版本协议只有一个请求单元
            try
            {
                using (BufferWriter writer = new BufferWriter())
                {
                    writer.Write(new byte[] { 1, 1 });  //写入版本1.1
                    
                    Int16 lcid = 2052;
                    writer.Write(lcid); //写入语言LCID

                    long token = 0;//v11的token为64位整形
                    long.TryParse(Token, out token);
                    writer.Write(token);    //写入Token
                    
                    writer.Write(rq.BusinessCode); //写入请求码
                    writer.Write(rq.FunctionCode);
                    if (rq.OnWriteRequest != null)  //写入业务数据
                        rq.OnWriteRequest(writer);

                    byte[] requestBuffer = writer.ToArray(); //所有的请求缓冲数据
                    IServiceProxy service = ServiceProxyFactory.Create(ServiceUrl); //创建 请求代理
                    
                    //发送到服务器代理
                    service.Process(
                        requestBuffer,
                        responseBuffer => //响应处理
                        {
                            BufferReader reader = new BufferReader(responseBuffer);
                            reader.ReadBytes(2);//版本
                            rq.ResponseCode = (ResponseCode)reader.ReadInt32(); //读响应码
                            reader.ReadInt32(); //业务码、功能码
                            if ((rq.ResponseCode & ResponseCode.ApplicationError) != 0)
                            {
                                HandleException(rq, new ServiceAppException(rq.ResponseCode));
                            }
                            else if ((rq.ResponseCode & ResponseCode.SystemError) != 0)
                            {
                                HandleException(rq, new ServiceBadRequestException(rq.ResponseCode));
                            }
                            else if (rq.OnReadResponse != null) //如果业务定义了响应处理则调用之
                            {
                                //rq.OnReadResponse(reader);
                                SynchronizeThead(reader, rq.OnReadResponse); //结果线程同步
                            }
                        },
                        exception =>  //异常处理
                        {
                            HandleException(rq, new ServiceCommException(exception));
                        });
                }
            }
            catch (Exception exception)
            {
                HandleException(rq, new ServiceCommException(exception));
            }
        }

        /// <summary>
        /// 处理异常
        /// </summary>
        /// <param name="request"></param>
        /// <param name="exception"></param>
        protected void HandleException(ClientRequest request, Exception exception)
        {
            SynchronizeThead(exception, (ex) => //异常信息线程同步
           {
               if (request.OnError != null)
               {
                   request.OnError(ex);
               }
               else
               {
                   throw ex;
               }
           }
           );
        }

        /// <summary>
        /// 处理线程同步
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="cb"></param>
        protected void SynchronizeThead<T>(T obj, Action<T> cb)
        {
            sysContext.Post((state) => cb((T)state), obj);
        }

        /// <summary>
        /// 授权码
        /// </summary>
        public string Token { get; set; }

        /// <summary>
        /// 服务器地址
        /// </summary>
        public string ServiceUrl{get;set;}


    }
}
